#include "memory_pool.h"
#include <malloc.h>
#include <stdint.h>
#include <iostream>
//测试用的
int small_count=1;  //小内存块个数
int large_count=0;  //大内存块个数
void memory_pool::init()
{
    this->pool=(node *)malloc(BLOCK_SIZE);
    if(pool==nullptr){
        perror("初始化失败");
    }
    pool->cur=&this->pool->head;
    pool->large=nullptr;
    pool->head.failed_num=0;
    pool->head.next=nullptr;
    pool->head.refer_count=0; //引用计数
    pool->head.end=(u_char *)pool+BLOCK_SIZE;
    pool->head.last=(u_char *)pool +sizeof(node);
    

}

void *memory_pool::alloc_mem(int size)
{
    if(size<SIZE_OF_LARGE){
        return this->alloc_small_mem(size);
    }else{
        return this->alloc_large_mem(size);
    }
   
}

void memory_pool::reset_pool()
{
    //大块内存的处理
    large_node *p=pool->large;
    while(p){
        if(p->alloc){
            free(p->alloc);
            p->alloc=nullptr;
        }
        p=p->next;
    }
    pool->large=nullptr;    //这里必须置空，由于large节点本来就是从小块内存里申请的，小内存置空，表示这些节点也得没用
    //小块内存的处理
    small_node * now=&pool->head;
    now->failed_num=0;
    now->refer_count=0;
    now->last=(u_char *)pool+sizeof(node);
    now=now->next;
    while(now){
        now->failed_num=0;
        now->refer_count=0;
        now->last=(u_char *)now+sizeof(small_node);
        now=now->next;
    }

}

memory_pool::~memory_pool()
{
    //释放内存，先释放大内存
    int num=0;
    large_node *large=pool->large;
    while(large){
        if(large->alloc){
            free(large->alloc);    //这里置不置空都无所谓了
        }
        num++;
        large=large->next;

    }
    std::cout<<"释放"<<num<<"大块"<<std::endl;
    //上面没有释放掉large节点本身，是因为large节点本身都是再小内存块里申请的，到时候小内存块释放时，一块搞定
    small_node * p=pool->head.next; //因为第一块不是申请的
    small_node * q=nullptr;
    int time=1;
    while(p){
        q=p->next;
        free(p);
        p=q;
        time++;
        
    }
    free(pool); //最后释放掉pool就好了
    std::cout<<"释放"<<time<<"小块"<<std::endl;
}

void *memory_pool::alloc_small_mem(int size)
{
    small_node * now=pool->cur;
    while(now){

        now->last=(u_char *)align_ptr(now->last);
        if(now->end-now->last>=size){
            //当前块可以分配
            std::cout<<"本次申请的内存块中还有："<<now->end-now->last<<std::endl;
            u_char *tmp=now->last;  //保存返回指针
            now->last+=size;    //掠过size
            now->refer_count++;
            return tmp;
        }
        now=now->next;
    }
    return alloc_new_small_mem(size);
}

void *memory_pool::alloc_large_mem(int size)
{
    
    void * alloc=malloc(size);  //这是需要的内存块  后续直接返回
    if(alloc==nullptr){
        perror("大块内存申请失败");
        return nullptr;
    }

    //去查找目前有没有空的large
    large_node *p=pool->large;
    //找5次就不找
    int times=5;
    while(p&&times){
        if(p->alloc==nullptr){
            p->alloc=alloc;
            return alloc;   //找到那就直接返回就好了
        }
        p=p->next;
        times--;
    }

    large_node * large=(large_node *)this->alloc_small_mem(sizeof(large_node));
    if(large==nullptr){
        free(alloc);
        perror("大块内存申请失败1");
        return nullptr;
    }

    large->alloc=alloc;
    if(pool->large==nullptr){
        pool->large=large;
        large->next=nullptr;
    }else{
        //进行头插即可
        large->next=pool->large;
        pool->large=large;
    }
    large_count++;

    return alloc;
}

void *memory_pool::alloc_new_small_mem(int size)
{
    //此时内存块不够了，我需要手动申请
    small_node *new_node=nullptr;
    new_node=(small_node *)malloc(BLOCK_SIZE);
    if(new_node==nullptr){
        perror("小内存块不够,此时也申请失败了");
        return nullptr;
    }
    new_node->failed_num=0;
    new_node->refer_count=1;
    new_node->end=(u_char *)new_node+BLOCK_SIZE;
    new_node->next=nullptr;
    new_node->last=(u_char *)new_node+sizeof(small_node);
    new_node->last=(u_char *)this->align_ptr(new_node->last);   //字节对齐
    u_char * res=new_node->last;    //这是后面要返回的
    new_node->last+=size;
    //我需要将其加入pool中
    small_node *p=pool->cur;
    while(p->next){
        if(p->failed_num>=(FAILED_TIMES-1)){

            pool->cur=p;        //这个往后指，后续可以加快分配，减少遍历
        }else{
            p->failed_num++;
        }
        p=p->next;
    }
    p->next=new_node;
    std::cout<<"当前内存块不够,又申请了一块"<<std::endl;
    small_count++;
    return res;
}

void *memory_pool::align_ptr(void *ptr)
{
    uintptr_t aligned_address = (uintptr_t)ptr;     //将指针转换为值（整型）
    aligned_address = (aligned_address+PTR_ALIGN_SIZE-1) & ~(PTR_ALIGN_SIZE - 1);   //方便进行与或运算
    return (void*)aligned_address;
}
